#include "app_att7022eu.h"

/*************************define****************************************/
struct rt_spi_device *spi_att7022eu;//spi设备
total_protect_data get_total_protect_data = {0};//总保数据
total_protect_data *gtpd = &get_total_protect_data;
/*************************extern****************************************/
extern dev_config dev_config_info;
extern struct rt_messagequeue mq_net_send;   		//发送数据消息队列
/*************************rt_thread************************************/
struct rt_thread get_att7022eu_data_thread;//线程控制
/*************************rt_stack*************************************/
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_get_att7022eu_data_thread_stack[2048];//线程栈 
/*************************rt_sem***************************************/
struct rt_semaphore sem_att7022eu_available;//采集可用信号量
/*******************************************************************************
* Function Name  : att7022eu_read
* Description    : 读取att7022寄存器数据
* Input          : reg 寄存器地址
* Return         : rt_uint32_t 寄存器的值
* Attention		   : None
*******************************************************************************/
rt_uint32_t att7022eu_read(struct rt_spi_device *dev,rt_uint8_t reg)
{
	rt_uint32_t read_data = 0;
	rt_uint8_t  receive_data[4] = {0};
	
	if(rt_spi_send_then_recv(dev,&reg,1,&receive_data,3) == RT_EOK)
	{
		read_data = (receive_data[0]<<16) | (receive_data[1]<<8) | receive_data[2];
		return read_data;
	}
	return RT_ERROR;
}
/*******************************************************************************
* Function Name  : att7022eu_write
* Description    : 写ATT7022EU寄存器值
* Input          : reg 寄存器地址ַ data 要写入的值
* Return         : rt_eok | rt_error
* Attention		   : None
*******************************************************************************/
int att7022eu_write(struct rt_spi_device *dev,rt_uint8_t reg,rt_uint32_t data)
{
	rt_uint8_t send_data[5] = {0};
	 
	send_data[0] = reg | 0x80;
  send_data[1] = ((data&0xFF0000) >> 16);
	send_data[2] = ((data&0xFF00) >> 8);
	send_data[3] =   data&0xFF;
	
	if(rt_spi_send(dev,send_data,4) == 4)
	{
		return RT_EOK;
	}
	return RT_ERROR;
}

/*******************************************************************************
* Function Name  : att7022eu_init
* Description    : ATT7022EU初始化
* Input          : void
* Return         : rt_uint32_t RT_EOK
* Attention		   : None
*******************************************************************************/
rt_uint32_t att7022eu_init(struct rt_spi_device *dev)
{
	rt_pin_mode(ATT7022EU_RST_PIN, PIN_MODE_OUTPUT);
	rt_pin_write(ATT7022EU_RST_PIN, PIN_LOW);
	rt_thread_mdelay(100);
	rt_pin_write(ATT7022EU_RST_PIN, PIN_HIGH);
	rt_thread_mdelay(100);

	//配置SPI工作模式
	struct rt_spi_configuration cfg;
	cfg.data_width = 8;
	cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_1 | RT_SPI_MSB;
	cfg.max_hz = 400 *1000;                           /* 400K */
	
	rt_spi_configure(dev, &cfg);
	
	att7022eu_write(dev,ATT7022EU_REG_RST,ATT7022EU_DATA_RST);//软复位
	
	rt_thread_mdelay(100);	
	
	return att7022eu_read(dev,ATT7022EU_REG_ID);
}

/*******************************************************************************
* Function Name  : start_7022eu
* Description    : 配置att7022eu
* Input          : void
* Return         : rt_uint32_t RT_EOK
* Attention		   : None
*******************************************************************************/
void start_att7022eu(struct rt_spi_device *dev)
{
		att7022eu_write(dev,0xC3,0x000000);//清除校表数据
		att7022eu_write(dev,0xC9,0x00005A);//打开校准数据写
		att7022eu_write(dev,0x01,0x00B9FE);//填写模式配置寄存器
		att7022eu_write(dev,0x03,0x00F804);//填写EMU配置单元寄存器
		att7022eu_write(dev,0x02,0x000000);//各路ADC增益均为1
		att7022eu_write(dev,0x31,0x003437);//填写模拟模块使能寄存器
		att7022eu_write(dev,0x6D,0x00FF00);//
		att7022eu_write(dev,0x6E,0x000DB8);//
		att7022eu_write(dev,0x6F,0x00D1DA);//
		att7022eu_write(dev,0xBF,0x000000);
}
/*******************************************************************************
* Function Name  : calibration_att7022eu
* Description    : 写入att7022eu校准数据
* Input          : void
* Return         : rt_uint32_t RT_EOK
* Attention		   : None
*******************************************************************************/
void calibration_att7022eu()
{
	rt_uint32_t idx = 0;
	att7022eu_write(spi_att7022eu,0x17,dev_config_info.vol_gain.voltage_A);
	att7022eu_write(spi_att7022eu,0x18,dev_config_info.vol_gain.voltage_B);
	att7022eu_write(spi_att7022eu,0x19,dev_config_info.vol_gain.voltage_C);
	att7022eu_write(spi_att7022eu,0x1A,dev_config_info.cur_gain.gain_current_A);
	att7022eu_write(spi_att7022eu,0x27,dev_config_info.cur_offset.offset_current_A);
	att7022eu_write(spi_att7022eu,0xC9,0x000000);//关闭校准数据写 - 1
	
	att7022eu_write(spi_att7022eu,0xC6,0x5A);
	
	for(idx = 1;idx < 58;idx++)
	{
		get_total_protect_data.checksum_first += att7022eu_read(spi_att7022eu,idx);
	}
	get_total_protect_data.checksum_first &= 0x00FFFFFF;
	
	for(idx = 96;idx < 114;idx++)
	{
		get_total_protect_data.checksum_second += att7022eu_read(spi_att7022eu,idx);
	}
	get_total_protect_data.checksum_second &= 0x00FFFFFF;
	 
	att7022eu_write(spi_att7022eu,0xC6,0);
}

/*******************************************************************************
* Function Name  : read_vol_phase
* Description    : 读取相电压并处理
* Input          : rt_uint8_t  1 - A 2 - B 3- C
* Return         : None
* Attention		   : None
*******************************************************************************/
void read_vol_phase(rt_uint8_t phase)
{

	if(phase > 3)
	{
		return ;
	}

	rt_uint32_t read_reg_data = 0;
	
	read_reg_data = att7022eu_read(spi_att7022eu,0x0C+phase);//相电压寄存器值

	gtpd->get_line_data[phase].vol_value = (rt_uint32_t)(read_reg_data/8192.0);//相电压实际值
}

/*******************************************************************************
* Function Name  : read_cur_a
* Description    : 读取相漏电流并处理
* Input          : rt_uint8_t phase
* Return         : None
* Attention		   : None
*******************************************************************************/
void read_cur_phase(rt_uint8_t phase)
{
	if(phase > 3)
	{
		return ;
	}
	
	rt_uint32_t read_reg_data = 0;
	
	rt_uint32_t get_cur_data = 0;
	
	read_reg_data = att7022eu_read(spi_att7022eu,0x0F+phase);//相电流寄存器值
	
	get_cur_data = (rt_uint32_t)(read_reg_data/8192.0*100);//相实际电流值
	
	gtpd->get_line_data[phase].cur_value = get_cur_data;
}
/*******************************************************************************
* Function Name  : get_att7021eu_data_thread_entry
* Description    : 获取ATT7022EU数据
* Input          : const char*
* Return         : None
* Attention		   : None
*******************************************************************************/
void get_att7021eu_data_thread_entry(void* parameter)
{
//	rt_uint8_t idx = 0;
 	rt_thread_mdelay(3000);
	while(1)
	{
					rt_thread_mdelay(100);
					if((att7022eu_read(spi_att7022eu,0x3E) == gtpd->checksum_first)&&(att7022eu_read(spi_att7022eu,0x5E) == gtpd->checksum_second))
					{
								rt_sem_take(&sem_att7022eu_available,RT_WAITING_FOREVER);//获取att7022使用权
						
								read_vol_phase(PHASE_A);

								read_vol_phase(PHASE_B);
							
								read_vol_phase(PHASE_C);
						
								read_cur_phase(PHASE_A);
						
							 rt_sem_release(&sem_att7022eu_available);	
					}
	}
}

/*******************************************************************************
* Function Name  : a_vol_timeout_entry
* Description    : A相下桩头失电报警定时器 
* Input          : void* paramete
* Return         : void
* Attention		   : None
*******************************************************************************/
void a_vol_timeout_entry(void* parameter)
{
	gtpd->get_line_data[1].vol_alarm_timer_sta = RT_FALSE;
	gtpd->get_line_data[1].vol_alarm_send = RT_TRUE;
}
/*******************************************************************************
* Function Name  : b_vol_timeout_entry
* Description    : B相下桩头失电报警定时器
* Input          : void* paramete
* Return         : void
* Attention		   : None
*******************************************************************************/
void b_vol_timeout_entry(void* parameter)
{
	gtpd->get_line_data[2].vol_alarm_timer_sta = RT_FALSE;
	gtpd->get_line_data[2].vol_alarm_send = RT_TRUE;
}
/*******************************************************************************
* Function Name  : c_vol_timeout_entry
* Description    : C相下桩头失电报警定时器
* Input          : void* paramete
* Return         : void
* Attention		   : None
*******************************************************************************/
void c_vol_timeout_entry(void* parameter)
{
	gtpd->get_line_data[3].vol_alarm_timer_sta = RT_FALSE;
	gtpd->get_line_data[3].vol_alarm_send = RT_TRUE;
}
/*******************************************************************************
* Function Name  : dev_vol_timeout_entry
* Description    : 设备失电报警定时器
* Input          : void* paramete
* Return         : void
* Attention		   : None
*******************************************************************************/
void dev_vol_timeout_entry(void* parameter)
{
	gtpd->get_line_data[PILE_HEAD].vol_alarm_timer_sta = RT_FALSE;
	gtpd->get_line_data[PILE_HEAD].vol_alarm_send = RT_TRUE;
}
/*******************************************************************************
* Function Name  : app_init_att7022eu
* Description    : 初始化att7022eu
* Input          : void
* Return         : void
* Attention		   : None
*******************************************************************************/
int app_init_att7022eu(void)
{
		int result = RT_TRUE;
		rt_uint32_t  read = 0;
	
		rt_sem_init(&sem_att7022eu_available, "7022_sem", 1, RT_IPC_FLAG_PRIO);		
	
		//rt_pin_mode(AC_POWER_PIN,PIN_MODE_INPUT_PULLDOWN);//读取设备供电引脚
	
		/* 查找ATT7022EU SPI设备 */
		spi_att7022eu = (struct rt_spi_device *)rt_device_find(SPI_ATT7022EU_DEV_NAME);
		
		if(spi_att7022eu == RT_NULL)
		{
			rt_kprintf("can't find device spi %s\n",SPI_ATT7022EU_DEV_NAME);
			return RT_ERROR; 
		}
		else
		{
			read = att7022eu_init(spi_att7022eu);
			//rt_kprintf("%s id is %X\n",SPI_ATT7022EU_DEV_NAME,read);
		}
		
		start_att7022eu(spi_att7022eu); 
		
		if((dev_config_info.vol_gain.magic_word == MAGIC_WORD)&&(dev_config_info.cur_offset.magic_word == MAGIC_WORD)  
			&&(dev_config_info.cur_offset.magic_word == MAGIC_WORD))
		{
			calibration_att7022eu();
			// 创建静态线程 - 获取ATT7022EU数据
			rt_thread_init(&get_att7022eu_data_thread,                		//线程控制块
										 "getatt7022",                       						//线程名字，在shell里面可以看到
										 get_att7021eu_data_thread_entry,           	 	//线程入口函数
										 RT_NULL,                     		  						//线程入口函数参数
										 &rt_get_att7022eu_data_thread_stack[0],       	//线程栈起始地址
										 sizeof(rt_get_att7022eu_data_thread_stack),   	//线程栈大小
										 vol_cur_pro,    								  							//线程的优先级
										 20);                         		      				//线程时间片
			rt_thread_startup(&get_att7022eu_data_thread);
		}	
		else
		{
			result = RT_FALSE;
		}
		return result;
		
}
INIT_APP_EXPORT(app_init_att7022eu);



